﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.Core.Modelling.Primitives;
using ITAP.Core.Utils;
using ITAP.Core.Calculations;
using System.Drawing;
using ITAP.Core.Modelling;
using ITAP.ContourBuilder.Components;
using ITAP.ContourBuilder.Components.Dimensions;

namespace ITAP.ContourBuilder.Utils
{
    public class ContourUtils
    {



        public static ContourModel GetOffsetModel(ContourModel model, bool copyOffsets)
        {
            ContourModel newModel = ContourElementFactory.CreateModel();
            List<IPrimitive> offsetContour = new List<IPrimitive>();
            foreach(ContourElement element in model)
                offsetContour.Add(element.Primitive.GetOffsetPrimitive(element.Offset));

            for (int i = 0; i < offsetContour.Count; i++)
            {
                IEndedPrimitive endedPrimitive;
                IEndedPrimitive nextEndedPrimitive;
                IEndedPrimitive prevEndedPrimitive;

                endedPrimitive = offsetContour[i] as IEndedPrimitive;
                if (i == 0)
                {
                    nextEndedPrimitive = offsetContour[i + 1] as IEndedPrimitive;
                    prevEndedPrimitive = offsetContour[offsetContour.Count - 1] as IEndedPrimitive;
                }
                else if (i == offsetContour.Count - 1)
                {
                    nextEndedPrimitive = offsetContour[0] as IEndedPrimitive;
                    prevEndedPrimitive = offsetContour[i - 1] as IEndedPrimitive;
                }
                else
                {
                    nextEndedPrimitive = (IEndedPrimitive)offsetContour[i + 1];
                    prevEndedPrimitive = (IEndedPrimitive)offsetContour[i - 1];
                }
                ModelPoint[] prevIntersectionPoints = endedPrimitive.Intersect(prevEndedPrimitive, EndType.Start);
                ModelPoint[] nextIntersectionPoints = endedPrimitive.Intersect(nextEndedPrimitive, EndType.End);
                if (!ModelCalculations.IsErrorPoint(prevIntersectionPoints[0]))
                    endedPrimitive.StartPoint = prevIntersectionPoints[0];
                if (!ModelCalculations.IsErrorPoint(nextIntersectionPoints[0]))
                    endedPrimitive.EndPoint = nextIntersectionPoints[0];
            }

            IEndedPrimitive prevPrimitive = null;
            ContourElement prevElement = null;
            ContourElement firstElement = null;
            foreach (IPrimitive primitive in offsetContour)
            {
                if (prevPrimitive == null)
                {
                    prevPrimitive = primitive as IEndedPrimitive;
                    prevElement = ContourElementFactory.CreateContourElementFromPrimitive(prevPrimitive, "");
                    firstElement = prevElement;
                    newModel.AddInnerComponent(prevElement);
                    continue;
                }
                ContourConnector connector = ContourElementFactory.CreateConnector(prevPrimitive.EndPoint);
                ContourElement element1 = prevElement;
                ContourElement element2 = ContourElementFactory.CreateContourElementFromPrimitive(primitive, "");
                ContourConnectionProvider.Connect(element1, connector, EndType.End);
                ContourConnectionProvider.Connect(element2, connector, EndType.Start);
                newModel.AddInnerComponent(connector);
                newModel.AddInnerComponent(element2);
                prevPrimitive = primitive as IEndedPrimitive;
                prevElement = element2;
            }

            ContourConnector _connector = ContourElementFactory.CreateConnector(prevPrimitive.EndPoint);
            ContourElement _element1 = prevElement;
            ContourElement _element2 = firstElement;

            ContourConnectionProvider.Connect(_element1, _connector, EndType.End);
            ContourConnectionProvider.Connect(_element2, _connector, EndType.Start);

            newModel.AddInnerComponent(_connector);

            if (copyOffsets)
            {
                List<double> offsets = new List<double>();
                foreach (ContourElement element in model)
                    offsets.Add(element.Offset);
                int counter = 0;
                foreach(ContourElement element in newModel)
                {
                    element.Offset = offsets[counter];
                    counter++;
                }
            }

            return newModel;
        }

        public static ModelPoint InvertPoint(ModelPoint pointToInvert, ModelPoint yAxisPoint)
        {
            ModelPoint pointRelativeYAxis = new ModelPoint(pointToInvert.X - yAxisPoint.X, pointToInvert.Y);
            pointRelativeYAxis.X = -pointRelativeYAxis.X;
            pointRelativeYAxis.X += yAxisPoint.X;
            return pointRelativeYAxis;
        }

        public static ContourContainer GetInvertContainer(ContourContainer container)
        {
            RectangleF innerBbox = container.InnerBoundingBox;
            ModelPoint center = new ModelPoint(innerBbox.X + innerBbox.Width / 2, innerBbox.Y + innerBbox.Height / 2);

            ContourContainer invertContainer = container.Clone() as ContourContainer;
            invertContainer.LeftIndent = container.RightIndent;
            invertContainer.RightIndent = container.LeftIndent;
            IEnumerable<IContourComponent> allComponents = invertContainer.GetAllInnerComponents();
            foreach (IContourComponent component in allComponents)
            {
                if (component is ContourElement)
                {
                    ContourElement element = component as ContourElement;
                    element.Height = -element.Height;
                }
                else if (component is ContourConnector || component is ContourHole || component is ContourText)
                {
                    component.MoveTo(ContourUtils.InvertPoint(component.Position, center));
                }
                else if (component is Dimension)
                {
                    Dimension dimension = component as Dimension;
                    dimension.ChangeTextDirection = !dimension.ChangeTextDirection;
                    if (dimension is ContourElementDimension)
                    {
                        (component as ContourElementDimension).OffsetFromPrimitive = -(component as ContourElementDimension).OffsetFromPrimitive;
                    }
                    else if(dimension is DiameterDimension)
                    {
                        // В случае размера диаметра меняем направление текста на прежнее (см. выше изменение направления текста).
                        dimension.ChangeTextDirection = !dimension.ChangeTextDirection;
                        DiameterDimension diameterDimension = dimension as DiameterDimension;
                        if (diameterDimension.Type == DiameterDimensionType.Left)
                            diameterDimension.Type = DiameterDimensionType.Right;
                        else
                            diameterDimension.Type = DiameterDimensionType.Left;
                    }
                    else if (dimension is OffsetFromMainBorderDimension)
                    {
                        dimension.ChangeTextDirection = !dimension.ChangeTextDirection;
                    }

                }
            }
            invertContainer.Update();
            return invertContainer;
        }



    }
}
